#include <cstdio>

#include <pthread.h>

#include "cameradaemon.h"
#include "timestamp.h"

using namespace cv;
void* captureThread(void* _cam){
    CameraDaemon* cam = (CameraDaemon*) _cam;
    cam->capture();
    return (void*) 0;
}

CameraDaemon::CameraDaemon()
{
    sem_init(&this->m_buffer_mutex, 0 ,1);
    this->m_working = false;
    this->m_from_file = false;
    this->m_interval = 0;
    this->m_width = 640;
    this->m_height = 480;
}

CameraDaemon::~CameraDaemon(){
    if(this->m_capture.isOpened()){
        this->m_working = false;
        pthread_cancel(this->m_capture_thread);
        this->m_capture.release();
    }
    printf("camera closed\t");
    TimeStamp::now()->print();
}



bool CameraDaemon::getImage(Mat &img, TimeStamp& t){
    sem_wait(&this->m_buffer_mutex);
    if(!this->m_buffer.data){
        sem_post(&this->m_buffer_mutex);
        return false;
    }else{
        this->m_buffer.copyTo(img);
        t = this->m_buffer_time;
        sem_post(&this->m_buffer_mutex);
        return true;
    }
}

bool CameraDaemon::startCapture(int device, int fps){
    this->m_device = device;
    this->m_fps = fps;
    this->m_interval = 1000 / this->m_fps;
    this->m_working = true;
    this->m_from_file = false;
    return (pthread_create(&this->m_capture_thread, NULL, &captureThread, (void*)this) == 0);
}

bool CameraDaemon::startCapture(std::string file, int fps){
    this->m_file = file;
    this->m_fps = fps;
    this->m_interval = 1000 / this->m_fps;
    this->m_working = true;
    this->m_from_file = true;
    return (pthread_create(&this->m_capture_thread, NULL, &captureThread, (void*)this) == 0);
}

void CameraDaemon::stopCapture(){
    pthread_cancel(this->m_capture_thread);
    if(this->m_capture.isOpened())
        this->m_capture.release();
}


void CameraDaemon::capture(){
    TimeStamp ts;
    if(!this->m_from_file){
        this->m_capture.open(this->m_device);
    }else{
        this->m_capture.open(this->m_file);
    }
    this->m_width = this->m_capture.get(CV_CAP_PROP_FRAME_WIDTH);
    this->m_height = this->m_capture.get(CV_CAP_PROP_FRAME_HEIGHT);
    while(this->m_working){
        Mat img;
        this->m_capture>>img;
        ts.setNow();
        if(img.empty()){
            if(this->m_from_file) {
                this->m_capture.open(this->m_file);
            }else{
                break;
            }
        }
        if(sem_wait(&this->m_buffer_mutex) == 0){
//            this->m_buffer = Mat(img);
            img.copyTo(this->m_buffer);
            this->m_buffer_time.setNow();
            sem_post(&this->m_buffer_mutex);
        }
        if(this->m_recording){
            this->m_record_writer.write(img);
        }
        img.release();

    }
    if(this->m_working){
        fprintf(stderr, "Error occurred when capturing!\n");
    }

}

void CameraDaemon::startRecord(){
    string fn = string();
//    fn.append(RECORD_FOLDER);
    fn.append(TimeStamp::now()->toFileName());
    fn.append(".avi");
    this->m_record_file = fn;
    this->m_record_writer = VideoWriter(this->m_record_file,
                                        CV_FOURCC('X','V','I','D'),
                                        this->m_fps,
                                        Size(this->m_width, this->m_height),
                                        true);
    this->m_recording = true;
}

void CameraDaemon::stopRecord(){
    this->m_recording = false;
    this->m_record_writer = VideoWriter();
}

void CameraDaemon::setBrightness(int f){

}

void CameraDaemon::setContrast(int c){

}

void CameraDaemon::setFocus(int f){

}

void CameraDaemon::setHeight(int h){

}

void CameraDaemon::setWidth(int w){

}
